%{
/*********************************************
2112433 石长伟
识别变量的计算
YACC file
**********************************************/
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#ifndef YYSTYPE
#define YYSTYPE double
#endif

typedef struct {
    char name[20];
    double value;
} Symbol;

static Symbol symbol_table[100]; // 符号表数组
static int symbol_count = 0; // 符号数量

int yylex();
extern int yyparse();
FILE* yyin;
double get_symbol_value(int index);
YYSTYPE assign_variable(int index, double value);
void yyerror(const char* s);
%}

//TODO:给每个符号定义一个单词类别
%token ADD MINUS
%token MULT DIV
%token UMINUS
%token LPAR RPAR
%token NUMBER 
%token ID
%token EQUAL

%left ADD MINUS
%left MULT DIV
%right UMINUS     
%left LPAR RPAR


%%


lines   :       lines expr ';' { printf("%f\n", $2); }
        |       lines assign ';' { printf("symbol table get %f\n",$2); }       
        |       lines ';'
        |       
        ;
//TODO:完善表达式的规则
expr    :       expr ADD expr   { $$=$1+$3; }
        |       expr MINUS expr   { $$=$1-$3;}
        |       expr MULT expr  {$$=$1*$3;}
        |       expr DIV expr   {$$=$1/$3;}
        |       LPAR expr RPAR  {$$=$2;}
        |       MINUS expr %prec UMINUS   {$$=-$2;}
        |       NUMBER  {$$=$1;}
        |       ID  {$$=get_symbol_value((int)$1);}
        ;
assign   :       ID EQUAL expr   {$$=assign_variable((int)$1,$3);}
%%

// programs section

int yylex()
{
    int t;
    while(1){
        t=getchar();
        if(t==' '||t=='\t'||t=='\n'){
            //do noting
        }else if(isdigit(t)){
            //TODO:解析多位数字返回数字类型 
            yylval=t-'0';
            t=getchar();
            while(isdigit(t)){
                yylval*=10;
                yylval+=t-'0';
                t=getchar();
            }
            ungetc(t,stdin);
            return NUMBER;
        }else if(isalpha(t)||t=='_'){
            char id[20];
            int i=0;
            id[i++]=t;
            t=getchar();
            while(isdigit(t)||isalpha(t)||t=='_'){
                id[i++]=t;
                t=getchar();
            }
            ungetc(t,stdin);
            id[i]='\0';
            //检查标识符是否已经在符号表中，在：ID就是索引，调用函数去找值
            for(int i=0;i<symbol_count;i++){
                if(strcmp(symbol_table[i].name,id)==0){
                    yylval=i;
                    return ID;
                }
            }
            //不在：ID就是新的索引，进入赋值语句
            strcpy(symbol_table[symbol_count].name,id);
            yylval=symbol_count++;
            return ID;
        }
        else if(t=='+'){
            return ADD;
        }else if(t=='-'){
            return MINUS;
        }//TODO:识别其他符号
        else if(t=='*'){
            return MULT;
        }else if(t=='/'){
            return DIV;
        }else if(t=='('){
            return LPAR;
        }else if(t==')'){
            return RPAR;
        }else if(t=='='){
            return EQUAL;
        }
        else{
            return t;
        }
    }
}

int main(void)
{
    yyin=stdin;
    do{
        yyparse();
    }while(!feof(yyin));
    return 0;
}
double get_symbol_value(int index){
    if(index >= 0 && index < symbol_count){
        return symbol_table[index].value;
    } else {
        fprintf(stderr, "Error: Symbol index out of range.\n");
        exit(1);
    }
}
double assign_variable(int index, double value){
    if(index >= 0 && index < symbol_count){
        symbol_table[index].value = value;
        return symbol_table[index].value;
    } else {
        fprintf(stderr, "Error: Symbol index out of range.\n");
        exit(1);
    }
}  
void yyerror(const char* s){
    fprintf(stderr,"Parse error: %s\n",s);
    exit(1);
}
